var Snake = require('./Snake');
var Food = require('./Food');
var Food_Mushroom = require('./Food_Mushroom');
/**
 *
 * @constructor
 */
function Grid(span, callback) {
  this.span = span || 40;
  this.callback = callback;
  this.snakes = [];
  this.foods = [];
  this._run();
}

Grid.prototype.receiveMsg = function (id, msg) {
  var snake = this.getSnake(id);
  if (msg) {
    switch (msg) {
      case 'revive':
        if (!snake || !snake.live) {
          this.push(id, true);
        }
        break;
      case 'up':
      case 'down':
      case 'left':
      case 'right':
        if (snake && snake.live) {
          snake.setDirection(msg);
        }
        break;
    }
  }
  return this;
}

Grid.prototype.push = function (id, revive) {
  var speed = Math.floor(Math.random() * 5 + 1), lifeBook = {}, x, y;
  console.log('speed=' + speed);
  this.snakes.forEach(function (snake) {
    snake.coordinates.forEach(function (coordinate) {
      lifeBook[coordinate.x + '' + coordinate.y] = 1;
    });
  });
  this.foods.forEach(function (food) {
    food.coordinates.forEach(function (coordinate) {
      lifeBook[coordinate.x + '' + coordinate.y] = 1;
    });
  });
  while (true) {
    x = Math.floor(Math.random() * this.span);
    y = Math.floor(Math.random() * (this.span - 2));
    if (!lifeBook[x + '' + y] && !lifeBook[x + '' + (y + 1)] && !lifeBook[x + '' + (y + 2)]) {
      this.snakes.push(new Snake(id).setProp({
        coordinates: [{x: x, y: y}, {x: x, y: y + 1}, {x: x, y: y + 2}],
        speed: speed,
        span: this.span,
        revive: !!revive
      }));
      break;
    }
  }
  return this._run();
}

Grid.prototype.getSnake = function (id) {
  return this.snakes.filter(function (snake) {
    return snake.id === id;
  })[0];
}

Grid.prototype.killSnake = function (id) {
  var snake = this.getSnake(id);
  if (snake) {
    snake.live = false;
  }
  return this;
}

Grid.prototype.revivedSnakes = function () {
  return this.snakes.filter(function (snake) {
    return snake.revive;
  });
}

Grid.prototype.deadSnakes = function () {
  return this.snakes.filter(function (snake) {
    return !snake.live;
  });
}

Grid.prototype._run = function () {
  var me = this;
  if (!this.intervalId) {
    this.intervalId = setInterval(function () {
      var hasSnake = me._hasSnake();
      me._clearDeadSnake()._createFoods()._nextStep()._check()._createFoods();
      if (hasSnake) {
        me.callback(me);
      } else {
        me._stop();
      }
    }, 400);
  }
  return this;
}

Grid.prototype._stop = function () {
  clearInterval(this.intervalId);
  this.intervalId = 0;
  return this;
}

Grid.prototype._createFoods = function () {
  var lifeBook = {}, x, y;
  this.foods = this.foods.filter(function (food) {
    return food.live;
  });
  if (this.foods.length < 3) {
    this.snakes.forEach(function (snake) {
      snake.coordinates.forEach(function (coordinate) {
        lifeBook[coordinate.x + '' + coordinate.y] = 1;
      });
    });
    this.foods.forEach(function (food) {
      food.coordinates.forEach(function (coordinate) {
        lifeBook[coordinate.x + '' + coordinate.y] = 1;
      });
    });
    while (this.foods.length < 3) {
      x = Math.floor(Math.random() * this.span);
      y = Math.floor(Math.random() * this.span);
      if (!lifeBook[x + '' + y]) {
        lifeBook[x + '' + y] = 1;
        if (Math.random() > 0.6) {
          this.foods.push(Food_Mushroom.create().setCoordinate([{x: x, y: y}]))
        } else {
          this.foods.push(Food.create().setCoordinate([{x: x, y: y}]));
        }
      }
    }
  }
  return this;
}

Grid.prototype._nextStep = function () {
  var me = this;
  me.snakes.forEach(function (snake) {
    snake.nextStep(me.foods);
  });
  return this;
}

Grid.prototype._hasSnake = function () {
  return this.snakes.length;
}

Grid.prototype._clearDeadSnake = function () {
  this.snakes = this.snakes.filter(function (snake) {
    return snake.live;
  });
  return this;
}

Grid.prototype._check = function () {
  var me = this, lifeBook = {};
  this.snakes.forEach(function (snake) {
    snake.coordinates.forEach(function (coordinate) {
      if (!lifeBook[coordinate.x + '' + coordinate.y]) {
        lifeBook[coordinate.x + '' + coordinate.y] = snake.id;
      } else {
        snake.live = false;
        me.killSnake(lifeBook[coordinate.x + '' + coordinate.y]);
      }
    });
  });
  return this;
}

module.exports = Grid;